package core

import (
	"fmt"
)

// 定义一些AOI的边界值
const (
	AOI_MIN_X  int = 85
	AOI_MAX_X  int = 410
	AOI_CNTS_X int = 10
	AOI_MIN_Y  int = 75
	AOI_MAX_Y  int = 400
	AOI_CNTX_Y int = 20
)

// AOI 区域管理模块
type AOIManager struct {
	// 区域的左边界坐标
	MinX int
	// 区域的右边界坐标
	MaxX int
	// X方向格子的数量
	CountX int
	// 区域的上边界坐标
	MinY int
	// 区域的下边界坐标
	MaxY int
	// Y方向格子的数量
	CountY int
	// 当前区域中有哪些格子map ke=格子的ID，value=格子的对象
	grids map[int]*Grid
}

// 初始化当前AOI 区域管理模块
func NewAOIManager(minX int, maxX int, countX int, minY int, maxY int, countY int) *AOIManager {
	aoiMgr := &AOIManager{
		MinX:   minX,
		MaxX:   maxX,
		CountX: countX,
		MinY:   minY,
		MaxY:   maxY,
		CountY: countY,
		grids:  make(map[int]*Grid),
	}
	// 给aoi初始化区域的格子所有的格子进行编号和初始化
	for y := 0; y < countY; y++ {
		for x := 0; x < countX; x++ {
			// 计算格子的ID 根据x,y编号
			// 格子编号: id = idy * countX + idx
			gid := y*countX + x
			aoiMgr.grids[gid] = NewGrid(
				gid,
				aoiMgr.MinX+x*aoiMgr.gridWidth(),
				aoiMgr.MinX+(x+1)*aoiMgr.gridWidth(),
				aoiMgr.MinY+y*aoiMgr.gridLength(),
				aoiMgr.MinY+(y+1)*aoiMgr.gridLength())
		}
	}
	return aoiMgr
}

// 得到每个格子在x轴方向的宽度
func (m *AOIManager) gridWidth() int {
	return (m.MaxX - m.MinX) / m.CountX
}

// 得到每个格子在x轴方向的长度
func (m *AOIManager) gridLength() int {
	return (m.MaxY - m.MinY) / m.CountY
}

// 打印格子消息
func (m *AOIManager) String() string {
	s := fmt.Sprintf("AOIManager: \n MinX:%d, MaxX:%d; CountX: %d; MinY:%d; MaxY:%d; CountY:%d \n", m.MinX, m.MaxX, m.CountX, m.MinY, m.MaxY, m.CountY)

	for _, grid := range m.grids {
		s += fmt.Sprintln(grid)
	}

	return s
}

// 根据格子GID得到周边九宫格格子的ID集合
func (m *AOIManager) GetSurroundGridsByGrid(gId int) (grids []*Grid) {
	// 判断gid是否在AOIManager中
	if _, ok := m.grids[gId]; !ok {
		return
	}
	// 将当前的gid本身加入九宫格切片中
	grids = append(grids, m.grids[gId])

	// 需要gid的左边是否有格子?右边是否有格子
	// 需要通过gId得到当前格子x轴编号 （gidX = gid % nx）
	gIdX := gId % m.CountX
	// 判断gidX编号左边还有格子, 如果有，则放在gIdsX集合中
	if gIdX > 0 {
		grids = append(grids, m.grids[gId-1])
	}
	// 判断gidX编号右边还有格子, 如果有，则放在gIdsX集合中
	if gIdX < m.CountX-1 {
		grids = append(grids, m.grids[gId+1])
	}

	//将x轴当前的格子都取出，进行遍历，再分别得到每个格子上下是否还有格子
	gIdsX := make([]int, 0, len(grids))
	for _, v := range grids {
		gIdsX = append(gIdsX, v.GId)
	}
	// 遍历gIdX集合中每个格子的gid
	for _, v := range gIdsX {
		// gid 上边是否还有格子
		gIdY := v / m.CountY
		if gIdY > 0 {
			grids = append(grids, m.grids[v-m.CountX])
		}
		// gid 下边是否还有格子
		if gIdY < m.CountY-1 {
			grids = append(grids, m.grids[v+m.CountX])
		}
	}

	return

}

// 通过横纵坐标得到所在的格子ID
func (m *AOIManager) GetGIdByPosition(x, y float32) int {
	idX := (int(x) - m.MinX) / m.gridWidth()
	idY := (int(y) - m.MinY) / m.gridLength()

	return idY*m.CountX + idX
}

// 通过横纵坐标得到周边九宫格内全部的PlayerIds
func (m *AOIManager) GetPlayerIdsByPosition(x, y float32) (playerIds []int) {
	// 得到当前玩家的GId格子id
	gId := m.GetGIdByPosition(x, y)
	// 通过GId 得到周边九宫格信息
	grids := m.GetSurroundGridsByGrid(gId)

	// 将九宫格的信息的全部的player的id累加到playerIds
	for _, grid := range grids {
		for pId, _ := range grid.playerIds {
			playerIds = append(playerIds, pId)
		}
	}

	return
}

// 添加一个playerId到一个格子中
func (m *AOIManager) AddPlayIdToGrid(pId, gId int) {
	m.grids[gId].Add(pId)
}

// 移除一个格子中的PlayerId
func (m *AOIManager) RemovePidFromGrid(pId, gId int) {
	m.grids[gId].Remove(pId)
}

// 通过GId获取全部的playerIds
func (m *AOIManager) GetPlayerIdByGId(gId int) (playerIds []int) {
	return m.grids[gId].GetPlayerIds()
}

// 通过坐标将Player添加到一个格子中
func (m *AOIManager) AddGridByPosition(pId int, x, y float32) {
	gId := m.GetGIdByPosition(x, y)
	m.AddPlayIdToGrid(pId, gId)
}

// 通过坐标把一个Player从一个格子中删除
func (m *AOIManager) RemovePlayerByPosition(pId int, x, y float32) {
	gId := m.GetGIdByPosition(x, y)
	m.RemovePidFromGrid(pId, gId)
}
